package com.wyd.core.common;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;
import tk.mybatis.mapper.entity.Example.OrderBy;

public class ExampleAdapter implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Class<?> clz;
	private Criterias criterias;

	public enum OrderType {
		DESC("desc"), ASC("asc");
		private String name;

		OrderType(String name) {
			this.name = name;
		}

		public String getName() {
			return name;
		}
	}

	public static final String IS_NULL = "isNull";
	public static final String IS_NOT_NULL = "isNotNull";
	public static final String EQUAL_TO = "equalTo";
	public static final String NOT_EQUAL_TO = "notEqualTo";
	public static final String GREATER_THAN = "greaterThan";
	public static final String GREATER_THAN_EQUAL_TO = "greaterThanOrEqualTo";
	public static final String LESS_THAN = "lessThan";
	public static final String LESS_THAN_EQUAL_TO = "lessThanOrEqualTo";
	public static final String IN = "in";
	public static final String NOT_IN = "notIn";
	public static final String BETWEEN = "between";
	public static final String NOT_BETWEEN = "notBetween";
	public static final String LIKE = "like";
	public static final String NOT_LIKE = "notLike";
	public static final String CONDITION = "condtion";
	public static final String CONDITIONS = "condtions";

	public static final String DESC = "desc";
	public static final String ASC = "asc";

	private Map<String, Boolean> orderBys = new HashMap<>();

	public ExampleAdapter orderBy(String property, OrderType type) {
		boolean isDesc = false;
		if (type.getName().equalsIgnoreCase(DESC)) {
			isDesc = true;
		}
		orderBys.put(property, isDesc);
		return this;
	}

	public ExampleAdapter(Class<?> clz) {
		this.clz = clz;
	}

	public Class<?> getClz() {
		return clz;
	}

	public Criterias createCriteria() {
		criterias = new Criterias();
		return criterias;
	}

	public Criterias getCriteria() {
		return criterias;
	}

	public static class Criterias implements Serializable {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		public List<Cri> cris = new ArrayList<>();

		public Criterias andIsNull(String property) {
			addCri("isNull", property);
			return (Criterias) this;
		}

		public Criterias andIsNotNull(String property) {
			addCri("isNotNull", property);
			return (Criterias) this;
		}

		public Criterias andEqualTo(String property, Object value) {
			addCri("equalTo", property, value);
			return (Criterias) this;
		}

		public Criterias andNotEqualTo(String property, Object value) {
			addCri("notEqualTo", property, value);
			return (Criterias) this;
		}

		public Criterias andGreaterThan(String property, Object value) {
			addCri("greaterThan", property, value);
			return (Criterias) this;
		}

		public Criterias andGreaterThanOrEqualTo(String property, Object value) {
			addCri("greaterThanOrEqualTo", property, value);
			return (Criterias) this;
		}

		public Criterias andLessThan(String property, Object value) {
			addCri("lessThan", property, value);
			return (Criterias) this;
		}

		public Criterias andLessThanOrEqualTo(String property, Object value) {
			addCri("lessThanOrEqualTo", property, value);
			return (Criterias) this;
		}

		public Criterias andIn(String property, Collection<?> values) {
			addCri("in", property, values);
			return (Criterias) this;
		}

		public Criterias andNotIn(String property, Collection<?> values) {
			addCri("notIn", property, values);
			return (Criterias) this;
		}

		public Criterias andBetween(String property, Object value1, Object value2) {
			addCri("between", property, value1, value2);
			return (Criterias) this;
		}

		public Criterias andNotBetween(String property, Object value1, Object value2) {
			addCri("notBetween", property, value1, value2);
			return (Criterias) this;
		}

		public Criterias andLike(String property, String value) {
			addCri("like", property, value);
			return (Criterias) this;
		}

		public Criterias andNotLike(String property, String value) {
			addCri("notLike", property, value);
			return (Criterias) this;
		}

		/**
		 * 手写条件
		 *
		 * @param condition
		 *            例如 "length(countryname)<5"
		 * @return
		 */
		public Criterias andCondition(String condition) {
			addCri("condtion", condition);
			return (Criterias) this;
		}

		/**
		 * 手写左边条件，右边用value值
		 *
		 * @param condition
		 *            例如 "length(countryname)="
		 * @param value
		 *            例如 5
		 * @return
		 */
		public Criterias andCondition(String condition, Object value) {
			addCri("condtions", condition, value);
			return (Criterias) this;
		}

		public void addCri(String type, String property) {
			this.addCri(type, property, null);
		}

		public void addCri(String type, String property, Object value) {
			this.addCri(type, property, value, null);
		}

		public void addCri(String type, String property, Collection<?> values) {
			this.addCri(type, property, values,null);
		}

		public void addCri(String type, String property, Object value1, Object value2) {
			Cri cri = new Cri();
			cri.type = type;
			cri.property = property;
			cri.firstValue = value1;
			cri.secondValue = value2;
			cris.add(cri);
		}
	}

	public static class Cri implements Serializable {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		public String type;
		public String property;
		public Object firstValue;
		public Object secondValue;
	}

	public static Example tran(Object adapters) {
		if (adapters instanceof ExampleAdapter) {
			ExampleAdapter adapter = (ExampleAdapter) adapters;
			Example example = new Example(adapter.getClz());
			Criteria criteria = example.createCriteria();
			List<Cri> cris = adapter.getCriteria().cris;
			for (int i = 0; i < cris.size(); i++) {
				Cri cri = cris.get(i);
				switch (cri.type) {
				case IS_NULL:
					criteria.andIsNotNull(cri.property);
					break;
				case IS_NOT_NULL:
					criteria.andIsNotNull(cri.property);
					break;
				case EQUAL_TO:
					criteria.andEqualTo(cri.property, cri.firstValue);
					break;
				case NOT_EQUAL_TO:
					criteria.andNotEqualTo(cri.property, cri.firstValue);
					break;
				case GREATER_THAN:
					criteria.andGreaterThan(cri.property, cri.firstValue);
					break;
				case GREATER_THAN_EQUAL_TO:
					criteria.andGreaterThanOrEqualTo(cri.property, cri.firstValue);
					break;
				case LESS_THAN:
					criteria.andLessThan(cri.property, cri.firstValue);
					break;
				case LESS_THAN_EQUAL_TO:
					criteria.andLessThanOrEqualTo(cri.property, cri.firstValue);
					break;
				case IN:
					criteria.andIn(cri.property, (Collection<?>) cri.firstValue);
					break;
				case NOT_IN:
					criteria.andNotIn(cri.property, (Collection<?>) cri.firstValue);
					break;
				case BETWEEN:
					criteria.andBetween(cri.property, cri.firstValue, cri.secondValue);
					break;
				case NOT_BETWEEN:
					criteria.andNotBetween(cri.property, cri.firstValue, cri.secondValue);
					break;
				case LIKE:
					criteria.andLike(cri.property, String.valueOf(cri.firstValue));
					break;
				case NOT_LIKE:
					criteria.andNotLike(cri.property, String.valueOf(cri.firstValue));
					break;
				case CONDITION:
					criteria.andCondition(cri.property);
					break;
				case CONDITIONS:
					criteria.andCondition(cri.property, cri.firstValue);
					break;
				}
			}
			if (!adapter.orderBys.isEmpty()) {
				Iterator<Entry<String, Boolean>> iterator = adapter.orderBys.entrySet().iterator();
				while (iterator.hasNext()) {
					Entry<String, Boolean> entry = (Entry<String, Boolean>) iterator
							.next();
					OrderBy orderBy = example.orderBy(entry.getKey());
					if (entry.getValue()) {
						orderBy.desc();
					}else{
						orderBy.asc();
					}
				}
			}
			return example;
		}
		return null;
	}
}
